import pytest
import requests
import pymysql
import time
import random
from uuid import uuid4

pytestmark=[pytest.mark.全链路测试案例]


# 测试配置
BASE_URL = "https://api.example.com"
DB_CONFIG = {
    "host": "db.example.com",
    "user": "test_user",
    "password": "test_password",
    "database": "ecommerce_db"
}

# 测试数据工厂
def generate_test_data():
    """生成唯一的测试数据，避免测试间干扰"""
    user_id = f"test_user_{uuid4().hex[:8]}"
    product_id = random.randint(1000, 9999)
    return {
        "username": user_id,
        "password": "TestPass123!",
        "product_id": product_id,
        "price": round(random.uniform(10, 100), 2),
        "quantity": random.randint(1, 5)
    }

# Fixture: 数据库连接
@pytest.fixture(scope="module")
def db_connection():
    conn = pymysql.connect(**DB_CONFIG)
    yield conn
    conn.close()

# Fixture: 创建测试用户
@pytest.fixture(scope="function")
def test_user(db_connection):
    test_data = generate_test_data()
    
    # 创建测试用户
    with db_connection.cursor() as cursor:
        cursor.execute(
            "INSERT INTO users (username, password, balance) VALUES (%s, %s, %s)",
            (test_data["username"], test_data["password"], 1000.00)
        )
        db_connection.commit()
    
    yield test_data
    
    # 测试后清理
    with db_connection.cursor() as cursor:
        cursor.execute("DELETE FROM orders WHERE user_id = %s", (test_data["username"],))
        cursor.execute("DELETE FROM payments WHERE user_id = %s", (test_data["username"],))
        cursor.execute("DELETE FROM users WHERE username = %s", (test_data["username"],))
        db_connection.commit()

# Fixture: 获取JWT Token
@pytest.fixture(scope="function")
def auth_headers(test_user):
    """登录获取JWT Token并返回认证头"""
    login_data = {
        "username": test_user["username"],
        "password": test_user["password"]
    }
    response = requests.post(f"{BASE_URL}/auth/login", json=login_data)
    assert response.status_code == 200
    token = response.json()["access_token"]
    return {"Authorization": f"Bearer {token}"}

# Fixture: 创建测试商品
@pytest.fixture(scope="function")
def test_product(db_connection, test_user):
    """创建测试商品并返回商品ID"""
    with db_connection.cursor() as cursor:
        cursor.execute(
            "INSERT INTO products (id, name, price, stock) VALUES (%s, %s, %s, %s)",
            (test_user["product_id"], f"Test Product", test_user["price"], 100)
        )
        db_connection.commit()
    return test_user["product_id"]

# 测试用例：支付全链路
def test_payment_full_workflow(test_user, auth_headers, test_product, db_connection):
    """
    测试支付全链路流程：
    1. 用户登录
    2. 创建订单
    3. 支付订单
    4. 查询订单状态
    5. 数据库验证全链路状态
    """
    
    # --- 阶段1: 创建订单 ---
    order_data = {
        "product_id": test_product,
        "quantity": test_user["quantity"]
    }
    
    order_response = requests.post(
        f"{BASE_URL}/orders",
        json=order_data,
        headers=auth_headers
    )
    
    # 验证订单创建响应
    assert order_response.status_code == 201
    order_id = order_response.json()["order_id"]
    expected_total = round(test_user["price"] * test_user["quantity"], 2)
    
    # 数据库验证 - 订单创建状态
    with db_connection.cursor(pymysql.cursors.DictCursor) as cursor:
        cursor.execute(
            "SELECT status, total_amount FROM orders WHERE id = %s", 
            (order_id,)
        )
        order_db = cursor.fetchone()
        assert order_db["status"] == "CREATED"
        assert float(order_db["total_amount"]) == expected_total
    
    # --- 阶段2: 支付订单 ---
    payment_data = {
        "order_id": order_id,
        "payment_method": "credit_card",
        "card_number": "4111111111111111"
    }
    
    payment_response = requests.post(
        f"{BASE_URL}/payments",
        json=payment_data,
        headers=auth_headers
    )
    
    # 验证支付响应
    assert payment_response.status_code == 202
    payment_id = payment_response.json()["payment_id"]
    
    # 等待支付处理（模拟异步处理）
    time.sleep(2)
    
    # --- 阶段3: 查询订单状态 ---
    order_status_response = requests.get(
        f"{BASE_URL}/orders/{order_id}",
        headers=auth_headers
    )
    
    # 验证订单状态更新
    assert order_status_response.status_code == 200
    order_status = order_status_response.json()["status"]
    assert order_status == "PAID"
    
    # --- 阶段4: 数据库验证全链路状态 ---
    with db_connection.cursor(pymysql.cursors.DictCursor) as cursor:
        # 验证订单状态
        cursor.execute(
            "SELECT status, total_amount FROM orders WHERE id = %s", 
            (order_id,)
        )
        order_db = cursor.fetchone()
        assert order_db["status"] == "PAID"
        
        # 验证支付记录
        cursor.execute(
            "SELECT status, amount FROM payments WHERE id = %s", 
            (payment_id,)
        )
        payment_db = cursor.fetchone()
        assert payment_db["status"] == "COMPLETED"
        assert float(payment_db["amount"]) == expected_total
        
        # 验证用户余额扣减
        cursor.execute(
            "SELECT balance FROM users WHERE username = %s", 
            (test_user["username"],)
        )
        user_balance = cursor.fetchone()["balance"]
        assert float(user_balance) == 1000.00 - expected_total
        
        # 验证库存扣减
        cursor.execute(
            "SELECT stock FROM products WHERE id = %s", 
            (test_product,)
        )
        product_stock = cursor.fetchone()["stock"]
        assert product_stock == 100 - test_user["quantity"]
        
        # 验证关联数据一致性
        cursor.execute("""
            SELECT o.status AS order_status, p.status AS payment_status
            FROM orders o
            JOIN payments p ON o.id = p.order_id
            WHERE o.id = %s
        """, (order_id,))
        relation_data = cursor.fetchone()
        assert relation_data["order_status"] == "PAID"
        assert relation_data["payment_status"] == "COMPLETED"

# Fixture: 模拟支付失败场景
@pytest.fixture
def mock_payment_failure(monkeypatch):
    """模拟支付服务失败"""
    def mock_post(*args, **kwargs):
        class MockResponse:
            status_code = 400
            def json(self):
                return {"error": "Payment declined"}
        return MockResponse()
    
    monkeypatch.setattr(requests, "post", mock_post)

# 测试用例：支付失败场景
def test_payment_failure_flow(test_user, auth_headers, test_product, db_connection, mock_payment_failure):
    """测试支付失败后的业务状态流转"""
    # 创建订单
    order_data = {"product_id": test_product, "quantity": test_user["quantity"]}
    order_response = requests.post(f"{BASE_URL}/orders", json=order_data, headers=auth_headers)
    order_id = order_response.json()["order_id"]
    
    # 尝试支付（会失败）
    payment_data = {"order_id": order_id, "payment_method": "credit_card"}
    payment_response = requests.post(f"{BASE_URL}/payments", json=payment_data, headers=auth_headers)
    assert payment_response.status_code == 400
    
    # 验证订单状态
    time.sleep(1)
    order_status_response = requests.get(f"{BASE_URL}/orders/{order_id}", headers=auth_headers)
    assert order_status_response.json()["status"] == "PAYMENT_FAILED"
    
    # 数据库验证
    with db_connection.cursor() as cursor:
        # 订单状态
        cursor.execute("SELECT status FROM orders WHERE id = %s", (order_id,))
        assert cursor.fetchone()[0] == "PAYMENT_FAILED"
        
        # 支付记录状态
        cursor.execute("SELECT status FROM payments WHERE order_id = %s", (order_id,))
        assert cursor.fetchone()[0] == "FAILED"
        
        # 用户余额不应变化
        cursor.execute("SELECT balance FROM users WHERE username = %s", (test_user["username"],))
        assert float(cursor.fetchone()[0]) == 1000.00
        
        # 库存不应变化
        cursor.execute("SELECT stock FROM products WHERE id = %s", (test_product,))
        assert cursor.fetchone()[0] == 100